import * as Cesium from "cesium"
import { defaultStyle } from "../style"
import type { DrawerStyle } from "../style"
import { ObservableArray } from "../../../utils/ObserverArray"
import { CesiumEventEmitter, EventType } from "../../EventEmitter"
//Cesium事件
export interface CesiumEvent {
  type: EventType
  callback: (...args: any[]) => void
}
//HTML事件
export interface HTMLElementEvent {
  el: HTMLElement | Document
  type: keyof HTMLElementEventMap
  callback: (...args: any[]) => void
}

export interface EventsConfig {
  cesiumEvents?: CesiumEvent[]
  elementEvents?: HTMLElementEvent[]
}

//绘制工具基类
export abstract class DrawerBase {
  constructor(
    public viewer: Cesium.Viewer,
    public styleOption?: DrawerStyle,
  ) {
    this.eventsHandler = new CesiumEventEmitter(this.viewer)
    this.scene = viewer.scene
    this.dataSource = new Cesium.CustomDataSource()
    this.entities = this.dataSource.entities
    this.viewer.dataSources.add(this.dataSource)
    this.featurePositions.onChange(this.updateVertexEntities)
    this.created()
  }
  //#region /*--------------------------------生命周期------------------------------*/
  created() {}
  beforeDestroy() {}
  //#endregion
  //#region /*--------------------------------状态----------------------------------*/
  //场景相关成员
  protected scene: Cesium.Scene //Cesium场景
  protected eventsHandler: CesiumEventEmitter //事件管理器
  protected dataSource: Cesium.CustomDataSource //用于创建Entities
  protected entities: Cesium.EntityCollection //用于收集本工具创建的所有Entity

  //编辑状态标识
  isEditing: boolean = false

  //鼠标位置的三维坐标
  protected mousePosition?: Cesium.Cartesian3

  //存放正在绘制要素的坐标
  protected featurePositions: ObservableArray<Cesium.Cartesian3> =
    new ObservableArray<Cesium.Cartesian3>([])

  //#endregion
  //#region /*------------------------------公共成员----------------------------------*/
  //用于存放绘制要素实体
  public data: Cesium.Entity[] = []

  //进入编辑状态
  public start() {
    if (!this.isEditing) {
      this.mousePosition = undefined
      this.createHelpers()
      this.enableEvents(this.events)
      this.enableEvents(this.globalEvents)
      this.isEditing = true
    }
  }

  //退出编辑状态
  public end() {
    if (this.isEditing) {
      this.removeEvents(this.events)
      this.removeEvents(this.globalEvents)
      this.removeHelpers()
      this.initStates()
      this.isEditing = false
    }
  }

  protected initStates() {
    this.featurePositions.value = []
  }

  //清空已经绘制的要素
  public clear() {
    this.data.forEach((item) => this.entities.remove(item))
    this.data = []
  }

  //销毁Drawer实例
  public destroy() {
    this.beforeDestroy()
    this.viewer.dataSources.remove(this.dataSource)
  }
  //#endregion

  //#region /*-----------------------------内部私有成员----------------------------------*/
  //辅助实体
  protected abstract helpers: Cesium.Entity.ConstructorOptions[] //辅助实体配置
  protected helperEntities: Cesium.Entity[] = [] //用于收集辅助实体
  protected vertexEntities: Cesium.Entity[] = [] //用于收集顶点辅助实体

  //创建辅助实体
  protected createHelpers() {
    this.helpers.forEach((item) => {
      this.mergeStyles(item)
      const entity = this.entities.add(item)
      this.helperEntities.push(entity)
    })
  }

  //删除辅助实体
  protected removeHelpers() {
    this.helperEntities.forEach((item) => this.entities.remove(item))
    this.helperEntities = []
  }

  //事件配置
  protected abstract events: EventsConfig

  //全局事件配置
  globalEvents: EventsConfig = {
    elementEvents: [
      // ctrl+z撤销
      {
        el: document,
        type: "keypress",
        callback: (event) => {
          if (event.ctrlKey && event.code === "KeyZ") {
            if (this.featurePositions.value.length > 0) {
              this.featurePositions.value.pop()
            } else {
              if (this.data.length > 0) {
                const entity = this.data.pop()
                if (entity) {
                  this.entities.remove(entity)
                }
              }
            }
          }
        },
      },
    ],
    cesiumEvents: [
      //更新鼠标位置
      {
        type: "mousemove",
        callback: (e: Cesium.ScreenSpaceEventHandler.MotionEvent) => {
          this.mousePosition = this.scene.pickPosition(e.endPosition)
        },
      },
    ],
  }

  //绑定事件
  protected enableEvents(events: EventsConfig) {
    const { cesiumEvents, elementEvents } = events
    cesiumEvents &&
      cesiumEvents.forEach((item) => {
        this.eventsHandler.on(item.type, item.callback)
      })
    elementEvents &&
      elementEvents.forEach((item) => {
        item.el.addEventListener(item.type, item.callback)
      })
  }

  //解绑事件
  protected removeEvents(events: EventsConfig) {
    const { cesiumEvents, elementEvents } = events
    cesiumEvents &&
      cesiumEvents.forEach((item) => {
        this.eventsHandler.off(item.type, item.callback)
      })
    elementEvents &&
      elementEvents.forEach((item) => {
        item.el.removeEventListener(item.type, item.callback)
      })
  }

  //绘制要素(并添加到data,触发onClose回调)
  protected drawFeature(option: Cesium.Entity.ConstructorOptions) {
    this.mergeStyles(option)
    const entity = this.entities.add(option)
    this.onClose && this.onClose(entity)
    this.data.push(entity)
    return entity
  }

  //合并样式
  protected mergeStyles(option: Cesium.Entity.ConstructorOptions): void {
    // 定义可合并的样式类型
    const styleTypes = ["point", "polyline", "polygon", "rectangle"] as const

    //合并样式
    styleTypes.forEach((type) => {
      if (option[type]) {
        option[type] = {
          ...defaultStyle[type], // 默认样式
          ...this.styleOption?.[type], // 用户样式
          ...option[type], // 方法传入样式
        } as any
      }
    })
  }

  //根据要素顶点数组更新绘制顶点实体
  private updateVertexEntities = () => {
    //遍历要素坐标，如果顶点实体数组中没有要素的坐标则创建
    this.featurePositions.value.forEach((position) => {
      if (
        !this.vertexEntities.find((item) =>
          position.equals(item.position?.getValue()),
        )
      ) {
        this.vertexEntities.push(
          this.entities.add({
            position,
            point: {
              ...defaultStyle.point,
              ...this.styleOption?.point,
            },
          }),
        )
      }
    })

    //遍历顶点实体数组，如果要素坐标中找不到Entity的坐标，则删除Entity
    this.vertexEntities = this.vertexEntities.filter((entity) => {
      const shouldVertexEntityDelete = !this.featurePositions.value.find(
        (position) => position.equals(entity.position?.getValue()),
      )
      if (shouldVertexEntityDelete) {
        this.entities.remove(entity)
      }
      return !shouldVertexEntityDelete
    })
  }

  //完成一个要素绘制时触发该回调
  public onClose?: (e: Cesium.Entity) => void
  //#endregion
}
